package de.mmis.core.base.gui;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.swing.JPanel;

import de.mmis.core.base.device.Device;
import de.mmis.core.base.event.Observer;

public abstract class AbstractGUIComponent<D> extends JPanel implements
		GUIComponent<D> {
	private static final long serialVersionUID = -6645895849509000966L;

	protected List<Observer<GUIEvent>> observers;

	private Device<D> device = null;

	protected ClassLoader classLoader;

	private long priority;
	private String defaultDisplayName;
	protected Class<?> applicableClass;

	/**
	 * creates {@link AbstractControlComponent} with given priority and display
	 * name
	 */
	public AbstractGUIComponent(long priority,
			Class<? super D> applicableClass, String defaultDisplayName) {
		this.priority = priority;
		this.applicableClass = applicableClass;
		this.defaultDisplayName = defaultDisplayName;
	}

	@Override
	public long getPriority() {
		return priority;
	}

	@Override
	public String getDisplayName(String languageCode) {
		return defaultDisplayName;
	}

	/**
	 * Fires the given event, i.e. distributes it to all registered observers (
	 * {@link Observer}s).
	 * 
	 * @param event
	 *            the event to fire
	 */
	protected void fireEvent(GUIEvent event) {
		synchronized (this.observers) {
			for (Observer<GUIEvent> observer : this.observers) {
				observer.notify(this, event);
			}
		}
	}

	@Override
	public void addObserver(Observer<GUIEvent> observer) {
		synchronized (this.observers) {
			this.observers.add(observer);
		}
	}

	@Override
	public void removeObserver(Observer<GUIEvent> observer) {
		synchronized (this.observers) {
			this.observers.remove(observer);
		}
	}

	@Override
	public String toString() {
		return getDisplayName("eng");
	}

	@Override
	public void initialize(Class<?> clazz, Device<D> device,
			ClassLoader classLoader) {
		this.observers = Collections
				.synchronizedList(new ArrayList<Observer<GUIEvent>>());
		this.device = device;
		this.classLoader = classLoader;
		initialize(clazz);
	}

	/**
	 * initialize this GUI component, creating its subcomponents and any
	 * additional objects needed.
	 * 
	 * @param clazz
	 *            runtime class of the device that should be controlled
	 */
	public abstract void initialize(Class<?> clazz);

	public Device<D> getDevice() {
		return this.device;
	}
}
